
package com.tools.cleanmaster.utils;

import android.util.Base64;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * @author wudanfeng
 */
public class RSACoder {
    static final String TAG = "RSACoder";
    public static final String KEY_ALGORITHM = "RSA";
    private static final int KEY_SIZE = 512;
    private static final String UTF8 = "UTF8";

    /**
     * 公钥加密
     *
     * @param data 待加密数据
     * @param key  用Base64加密后的密钥
     * @return Base64转换后的加密的数据
     */
    public static String encryptByPublicKey(String data, String key) {
        try {
            byte[] pkey = Base64.decode(key.getBytes(), Base64.DEFAULT);
            byte[] enByte = data.getBytes(UTF8);
            byte[] enData = encryptByPublicKey(enByte, pkey);
            return Base64.encodeToString(enData, Base64.NO_WRAP);
        } catch (Exception e) {
            if (FeatureConfig.DEBUG_LOG) {
                LogHelper.e(TAG, "err", e);
            }
        }

        return "";
    }

    /**
     * 公钥加密,超长数据分组加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

        int dataLength = data.length;
        int blockLength = KEY_SIZE / 8 - 11;
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        if (dataLength <= blockLength) {
            return cipher.doFinal(data);
        }
        ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        int hasRead = 0;
        while (hasRead < dataLength) {
            byte[] buffer;
            if ((dataLength - hasRead) < blockLength) {
                buffer = new byte[dataLength - hasRead];
                hasRead += dataLength - hasRead;
            } else {
                buffer = new byte[blockLength];
                hasRead += blockLength;
            }
            inputStream.read(buffer);
            outputStream.write(cipher.doFinal(buffer));
        }
        inputStream.close();
        outputStream.close();
        return outputStream.toByteArray();
    }
}
